#ifndef __MVT_HTTP_H__
#define __MVT_HTTP_H__

#include "mvdef.h"

MVCXX_EXTERN_BEGIN

/*********************************
 *       low level apis
 ********************************/
#define HTTP_CACHE_SIZE   4*1024
#define HTTP_URI_MAX_LEN  2*1024
#define HTTP_RSP_HDR_NUM  32
/**
 * @brief 分片方式读取请求body数据
 * 
 * @param pv8_cache       [in] 缓存空间
 * @param s32_size        [in] 缓存空间大小
 * @param s32_last_offset [in] 读取分片的位置
 * @param p_usr_data      [in] 用户数据
 * 
 * @note 当s32_last_offset = 0时，相当于告知实现方重新开始读取过程 \n 
 *       需要实现方重置读取状态到初始状态，否则可能会有不符合预期的请求表现
 */
typedef mv_s32_t(*p_on_slice_read_f)(mv_v8ptr_t pv8_cache, mv_s32_t s32_size, mv_s32_t s32_last_offset, mv_vptr_t p_usr_data);
typedef mv_s32_t(*p_on_trailer_fill_f)(mv_v8ptr_t pv8_cache, mv_s32_t s32_size, mv_vptr_t p_usr_data);
/**
 * @brief 分片方式输出响应body数据
 * 
 * @param pv8_cache       [in] 缓存空间
 * @param s32_size        [in] 数据大小
 * @param s32_total       [in] 响应的总大小
 * @param p_usr_data      [in] 用户数据
 * 
 */
typedef mv_s32_t(*p_on_slice_write_f)(mv_v8ptr_t pv8_cache, mv_s32_t s32_size, mv_s32_t s32_total, mv_vptr_t p_usr_data);

/**
 * @brief 响应头缓存结构
 * 
 */
typedef struct _hdr_item
{
    mv_v8ptr_t pv8_key;
    mv_v8ptr_t pv8_val;
}hdr_item_t;
/**
 * @brief 响应头列表hook，在收到响应头后，能通过此钩子通知调用者
 * 
 * @param cphdrs          [in] 响应头数组
 * @param s32_cnt         [in] 响应头KV数量
 * @param p_usr_data      [in] 用户数据
 * 
 */
typedef mv_s32_t(*p_rsp_hdr_hook_f)(const hdr_item_t *cphdrs, mv_s32_t s32_cnt, mv_vptr_t p_usr_data);

typedef struct _http_handle {
    /** 申请入参 */
    mv_s32_t           s32_req_hdr_size;  ///< 请求头缓存大小，一般申请1KB足够，视custom header需要扩展往上申请
    mv_s32_t           s32_req_body_size; ///< 请求内容缓存大小，根据实际业务响应一般满足容量申请(无法预先估算时，可以设置0，request_body_set时传入body或者slice回调)
    mv_s32_t           s32_rsp_hdr_size;  ///< 响应头缓存大小，一般申请1KB足够，视实际业务响应头需要扩展往上申请
    mv_s32_t           s32_rsp_body_size; ///< 响应内容缓存大小，根据实际业务响应一般满足容量申请
    p_rsp_hdr_hook_f   f_rsp_hdr_hook;    ///< （可选）响应header列表的通知回调
    p_on_slice_write_f f_on_slice_write;  ///< （可选）响应body的slice模式回调
    mv_vptr_t          p_usr_data;        ///< 用户数据(slice write回调携带)
    /** 申请出参 */
    mv_vptr_t          req;               ///< 请求句柄
    mv_vptr_t          rsp;               ///< 响应句柄
}mvt_http_t;

mv_s32_t mvt_http_new    (mvt_http_t *phdl);

mv_s32_t mvt_http_dispose(mvt_http_t *phdl);

/**
 * @brief log句柄单独设置接口（支持region）
 * 
 * @param phdl      [in] http句柄
 * @param phdl_log  [in] mvt log 句柄
 * @param u8_region [in] log句柄控制区域
 * @return 设置结果
 * - success : MV_EC_SUCCESS
 * -  failed : MV_EC_INVALID_ARGS
 *             MV_EC_NOT_INIT 
 *
 * @note mvt_log.h模块的log控制句柄，作为工具模块，允许设置作为外部主句柄的其中一个区域使用
 *       此接口设置后，后续接口动态入参的log句柄参数将忽略（接口不变只是为了兼容）
 */
mv_s32_t mvt_http_log_set(mvt_http_t *phdl, mv_vptr_t phdl_log, mv_u8_t u8_region);

/********************************************
 *              请求相关APIs
 *******************************************/ 
mv_s32_t mvt_http_request_uri_set      (mvt_http_t *phdl, mv_cv8ptr_t cpv8_uri);
mv_s32_t mvt_http_request_ca_dir_set   (mvt_http_t *phdl, mv_cv8ptr_t cpv8_dirpath);
/** 证书链数据形式设置的话，注意在http dispose之前，都不能把对应内存释放，否则会出现异常！ */
mv_s32_t mvt_http_request_ca_data_set  (mvt_http_t *phdl, mv_cv8ptr_t cpv8_datachain, mv_s32_t s32_len);
mv_s32_t mvt_http_request_method_set   (mvt_http_t *phdl, mv_cv8ptr_t cpv8_method, mv_cv8ptr_t cpv8_protocol);
mv_s32_t mvt_http_request_header_set   (mvt_http_t *phdl, mv_cv8ptr_t cpv8_key,    mv_cv8ptr_t cpv8_value);
mv_s32_t mvt_http_request_header_link  (mvt_http_t *phdl, mv_cv8ptr_t cpv8_hdrs);
mv_s32_t mvt_http_request_chunk_mode   (mvt_http_t *phdl);
mv_s32_t mvt_http_request_body_set     (mvt_http_t *phdl, mv_v8ptr_t pv8_body, mv_s32_t s32_len, p_on_slice_read_f f_on_slice_read, mv_vptr_t p_usr_data);
/** 重写已存在的目标请求头字段，注意长度必须保持一致，否则会有数据混乱情况，慎用！ */
mv_s32_t mvt_http_request_header_cover (mvt_http_t *phdl, mv_cv8ptr_t cpv8_key, mv_cv8ptr_t cpv8_value);
/** 清空请求头所有内容 */
mv_s32_t mvt_http_request_header_reset (mvt_http_t *phdl);
/** 从handle中，取出请求header块缓冲区首地址及当前长度（注意尽量不要直接修改里面的内容，仅用于调试打印使用）*/
mv_s32_t mvt_http_request_header       (mvt_http_t *phdl, mv_v8_t **ppv8_header);
/** 从handle中，取出请求body块缓冲区首地址 */
mv_s32_t mvt_http_request_body         (mvt_http_t *phdl, mv_v8_t **ppv8_body);
/** 从uri中，拿出CR部分([ scheme :][ // host:port][/ cr]) */
mv_s32_t mvt_http_request_cr           (mvt_http_t *phdl, mv_v8_t **ppv8_cr);
/** 从handle获取固定分配的slice cache(HTTP_CACHE_SIZE)，可以给特殊用途进行内存复用 */
mv_s32_t mvt_http_request_slice_cache  (mvt_http_t *phdl, mv_v8_t **ppv8_slice_cache);
/** 从handle已设定好的body内容和规则，计算出最终完整body的Content-MD5字段的值（属于可选字段，按需要调用） */
mv_s32_t mvt_http_request_body_md5     (mvt_http_t *phdl, mv_v8_t av8_md5_str[36]);
/** 从handle已设定好的body内容和规则，计算出最终完整body的Content-Type字段的值（属于可选字段，按需要调用） */
mv_s32_t mvt_http_request_body_cl      (mvt_http_t *phdl, mv_v8_t av8_cl_str[16]);

/********************************************
 *               响应相关APIs
 *******************************************/
/** 返回响应状态码 */
mv_s32_t mvt_http_response_status      (mvt_http_t *phdl);
/** 返回响应响应头的数量 */
mv_s32_t mvt_http_response_header      (mvt_http_t *phdl, hdr_item_t **pphdrs);
/** 返回响应body的长度 */
mv_s32_t mvt_http_response_body        (mvt_http_t *phdl, mv_v8_t **ppv8_body);

/**
 * @brief process a full http request
 * 
 * @param phdl           [in] http handle's entry
 * @param s32_timeout_ms [in] process timeout limit (ms)
 * @param p_mvt_log_hdl  [in] (optional)handle generated with "mvt_log.h -> mvt_log_init()" or NULL
 * @return process result
 * - success : > 0
 * -  failed : else
 * 
 * @note 与分离式HTTP请求互斥，注意不要混用
 */
mv_s32_t mvt_http_do(mvt_http_t *phdl, mv_s32_t s32_timeout_ms, mv_vptr_t p_mvt_log_hdl);

/**
 * @brief cancel & reset a http request (process)
 * 
 * @param phdl [in] http handle's entry
 * @return mv_s32_t 
 * - success : MV_EC_SUCCESS
 * -  failed : MV_EC_INVALID_ARGS
 */
mv_s32_t mvt_http_reset(mvt_http_t *phdl);

/**********************************
 *     分离式HTTP请求过程调用APIs
 *********************************/
/**
 * @brief start a http request (connect & send header)
 * 
 * @param phdl           [in] http handle's entry
 * @param s32_timeout_ms [in] process timeout limit (ms)
 * @param p_mvt_log_hdl  [in] (optional)handle generated with "mvt_log.h -> mvt_log_init()" or NULL
 * @return start process result
 * - success : MV_EC_SUCCESS
 * -  failed : else
 * 
 * @note 与一体式HTTP请求(mvt_http_do)互斥，注意不要混用 ！
 */
mv_s32_t mvt_http_start(mvt_http_t *phdl, mv_s32_t s32_timeout_ms, mv_vptr_t p_mvt_log_hdl);
/**
 * @brief send part(or all) of http request's body
 * 
 * @param phdl           [in] http handle's entry
 * @param cpv8_data      [in] body's data
 * @param ssz_len        [in] data size
 * @param s32_timeout_ms [in] process timeout limit (ms)
 * @return send result 
 * - success : length eq s32_len
 * -  failed : <= 0
 * 
 * @note 与一体式HTTP请求(mvt_http_do)互斥，注意不要混用 ！
 * @note 设置了chunked模式下，会自动填充分片大小信息，调用者无需关心
 */
mv_ssize_t mvt_http_send(mvt_http_t *phdl, mv_cv8ptr_t cpv8_data, mv_ssize_t ssz_len, mv_s32_t s32_timeout_ms);
/**
 * @brief recv data from http socket
 * 
 * @param phdl           [in] http handle's entry
 * @param pv8_data      [out] data's cache
 * @param ssz_len        [in] size of data willing to receive
 * @param s32_timeout_ms [in] process timeout limit (ms)
 * @return recv result 
 * - success : real length received
 * -  failed : <= 0
 * 
 * @note 与一体式HTTP请求(mvt_http_do)互斥，注意不要混用 ！
 * @attention 此接口仅限于websocket模式下使用，普通HTTP请求不要用此接口，否则可能影响正常通信！
 */
mv_ssize_t mvt_http_recv(mvt_http_t *phdl, mv_v8ptr_t pv8_data, mv_ssize_t ssz_len, mv_s32_t s32_timeout_ms);         ///< 模糊接收长度接口，有数据即返回(返回已接收量)
mv_ssize_t mvt_http_recv_ext(mvt_http_t *phdl, mv_v8ptr_t pv8_data, mv_ssize_t s32_ext_len, mv_s32_t s32_timeout_ms); ///< 精确接收长度接口，数据量达到才返回(超时返回已接收量)
/**
 * @brief fill request's body with padding datas
 * 
 * @param phdl           [in] http handle's entry
 * @param u8_pad         [in] padding data val
 * @param ssz_len        [in] padding size
 * @param s32_timeout_ms [in] process timeout limit (ms)
 * @return send result 
 * - success : MV_EC_SUCCESS
 * -  failed : < 0
 * 
 * @note 与一体式HTTP请求(mvt_http_do)互斥，注意不要混用 ！
 * @note 这是一个特殊用途send接口，用于在特殊需求场景下，需要连续插入相同数据内容的简化调用用法
 */
mv_s32_t mvt_http_send_pad(mvt_http_t *phdl, mv_u8_t u8_pad, mv_ssize_t ssz_len, mv_s32_t s32_timeout_ms);
/**
 * @brief send finish to server(if needed) & recv response
 * 
 * @param phdl           [in] http handle's entry
 * @param s32_timeout_ms [in] process timeout limit (ms)
 * @return end process result
 * - success : length of response body
 * -  failed : < 0
 * 
 * @note 与一体式HTTP请求(mvt_http_do)互斥，注意不要混用 ！
 */
mv_s32_t mvt_http_end  (mvt_http_t *phdl, mv_s32_t s32_timeout_ms);

MVCXX_EXTERN_END

#endif